MACRO(FLEX_TARGET_custom Name Input Output)
     SET(FLEX_TARGET_usage "FLEX_TARGET(<Name> <Input> <Output> [COMPILE_FLAGS <string>]")
     IF(${ARGC} GREATER 3)
       IF(${ARGC} EQUAL 5)
         IF("${ARGV3}" STREQUAL "COMPILE_FLAGS")
           SET(FLEX_EXECUTABLE_opts  "${ARGV4}")
           SEPARATE_ARGUMENTS(FLEX_EXECUTABLE_opts)
         ELSE()
           MESSAGE(SEND_ERROR ${FLEX_TARGET_usage})
         ENDIF()
       ELSE()
         MESSAGE(SEND_ERROR ${FLEX_TARGET_usage})
       ENDIF()
     ENDIF()
     ADD_CUSTOM_COMMAND(OUTPUT ${Output}
       #COMMAND ${FLEX_EXECUTABLE}
       #ARGS ${FLEX_EXECUTABLE_opts} -o\"${Output}\" ${Input}
       COMMAND ${FLEX_EXECUTABLE} ${FLEX_EXECUTABLE_opts} -o${Output} ${Input}
       VERBATIM
       DEPENDS ${Input}
       COMMENT "[FLEX][${Name}] Building scanner with flex ${FLEX_VERSION}"
       WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
     SET(FLEX_${Name}_DEFINED TRUE)
     SET(FLEX_${Name}_OUTPUTS "${Output}")
     SET(FLEX_${Name}_INPUT "${Input}")
     SET(FLEX_${Name}_COMPILE_FLAGS ${FLEX_EXECUTABLE_opts})
ENDMACRO(FLEX_TARGET_custom)

 # internal macro
 macro(BISON_TARGET_option_verbose_custom Name BisonOutput filename)
   list(APPEND BISON_TARGET_cmdopt "--verbose")
   get_filename_component(BISON_TARGET_output_path "${BisonOutput}" PATH)
   get_filename_component(BISON_TARGET_output_name "${BisonOutput}" NAME_WE)
   add_custom_command(OUTPUT ${filename}
     COMMAND ${CMAKE_COMMAND} -E copy
     "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output"
     "${filename}"
     VERBATIM
     DEPENDS
     "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output"
     COMMENT "[BISON][${Name}] Copying bison verbose table to ${filename}"
     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
   set(BISON_${Name}_VERBOSE_FILE ${filename})
   list(APPEND BISON_TARGET_extraoutputs
     "${BISON_TARGET_output_path}/${BISON_TARGET_output_name}.output")
 endmacro()

MACRO(BISON_TARGET_custom Name BisonInput BisonOutput)
  SET(BISON_TARGET_output_header "")
  #SET(BISON_TARGET_command_opt "")
  SET(BISON_TARGET_cmdopt "")
  SET(BISON_TARGET_outputs "${BisonOutput}")
  IF(NOT ${ARGC} EQUAL 3 AND
     NOT ${ARGC} EQUAL 5 AND
     NOT ${ARGC} EQUAL 7 AND
     NOT ${ARGC} EQUAL 9)
    MESSAGE(SEND_ERROR "Usage")
  ELSE()
    # Parsing parameters
    IF(${ARGC} GREATER 5 OR ${ARGC} EQUAL 5)
      IF("${ARGV3}" STREQUAL "VERBOSE")
        BISON_TARGET_option_verbose_custom(${Name} ${BisonOutput} "${ARGV4}")
      ENDIF()
      IF("${ARGV3}" STREQUAL "COMPILE_FLAGS")
        BISON_TARGET_option_extraopts("${ARGV4}")
      ENDIF()
      IF("${ARGV3}" STREQUAL "HEADER")
        set(BISON_TARGET_output_header "${ARGV4}")
      ENDIF()
    ENDIF()

    IF(${ARGC} GREATER 7 OR ${ARGC} EQUAL 7)
      IF("${ARGV5}" STREQUAL "VERBOSE")
        BISON_TARGET_option_verbose_custom(${Name} ${BisonOutput} "${ARGV6}")
      ENDIF()
    
      IF("${ARGV5}" STREQUAL "COMPILE_FLAGS")
        BISON_TARGET_option_extraopts("${ARGV6}")
      ENDIF()

      IF("${ARGV5}" STREQUAL "HEADER")
        set(BISON_TARGET_output_header "${ARGV6}")
      ENDIF()
    ENDIF()

    IF(${ARGC} EQUAL 9)
      IF("${ARGV7}" STREQUAL "VERBOSE")
        BISON_TARGET_option_verbose_custom(${Name} ${BisonOutput} "${ARGV8}")
      ENDIF()
    
      IF("${ARGV7}" STREQUAL "COMPILE_FLAGS")
        BISON_TARGET_option_extraopts("${ARGV8}")
      ENDIF()

      IF("${ARGV7}" STREQUAL "HEADER")
        set(BISON_TARGET_output_header "${ARGV8}")
      ENDIF()
    ENDIF()

    IF(BISON_TARGET_output_header)
        # Header's name passed in as argument to be used in --defines option
        LIST(APPEND BISON_TARGET_cmdopt
             "--defines=${BISON_TARGET_output_header}")
        set(BISON_${Name}_OUTPUT_HEADER ${BISON_TARGET_output_header})
    ELSE()
        # Header's name generated by bison (see option -d)
        LIST(APPEND BISON_TARGET_cmdopt "-d")
        STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\2" _fileext "${ARGV2}")
        STRING(REPLACE "c" "h" _fileext ${_fileext})
        STRING(REGEX REPLACE "^(.*)(\\.[^.]*)$" "\\1${_fileext}" 
            BISON_${Name}_OUTPUT_HEADER "${ARGV2}")
    ENDIF()

    LIST(APPEND BISON_TARGET_outputs "${BISON_${Name}_OUTPUT_HEADER}")
      
    ADD_CUSTOM_COMMAND(OUTPUT ${BISON_TARGET_outputs}
      ${BISON_TARGET_extraoutputs}
      #COMMAND ${BISON_EXECUTABLE}
      #ARGS ${BISON_TARGET_cmdopt} -o\"${ARGV2}\" ${ARGV1}
      COMMAND ${BISON_EXECUTABLE} ${BISON_TARGET_cmdopt} -o ${BisonOutput} ${BisonInput}
      VERBATIM
      DEPENDS ${ARGV1}
      COMMENT "[BISON][${Name}] Building parser with bison ${BISON_VERSION}"
      WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
  
    # define target variables
    SET(BISON_${Name}_DEFINED TRUE)
    SET(BISON_${Name}_INPUT "${ARGV1}")
    SET(BISON_${Name}_OUTPUTS "${BISON_TARGET_outputs}")
    SET(BISON_${Name}_COMPILE_FLAGS "${BISON_TARGET_cmdopt}")
    SET(BISON_${Name}_OUTPUT_SOURCE "${BisonOutput}")

  ENDIF(NOT ${ARGC} EQUAL 3 AND
        NOT ${ARGC} EQUAL 5 AND
        NOT ${ARGC} EQUAL 7 AND
        NOT ${ARGC} EQUAL 9)
ENDMACRO(BISON_TARGET_custom)

MACRO(FIND_BISON_costum)
	FIND_PROGRAM(BISON_EXECUTABLE NAMES bison yacc byacc)

	IF(BISON_EXECUTABLE)
		SET(BISON_FOUND TRUE)

		EXECUTE_PROCESS(COMMAND ${BISON_EXECUTABLE} --version
			OUTPUT_VARIABLE _BISON_VERSION
		)
		string (REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" BISON_VERSION "${_bison_VERSION}")
	ENDIF(BISON_EXECUTABLE)

	IF(BISON_FOUND)
	  IF(NOT Bison_FIND_QUIETLY)
		MESSAGE(STATUS "Found Bison: ${BISON_EXECUTABLE}")
	  ENDIF(NOT Bison_FIND_QUIETLY)
	ELSE(BISON_FOUND)
	  IF(Bison_FIND_REQUIRED)
		MESSAGE(FATAL_ERROR "Could not find Bison")
	  ENDIF(Bison_FIND_REQUIRED)
	ENDIF(BISON_FOUND)
ENDMACRO(FIND_BISON_costum)

#Recursively add subdirectories that include header files
MACRO(HEADER_DIRECTORIES return_list location_pattern)
	SET(HEADER_DIRECTORIES_usage "HEADER_DIRECTORIES(<return_list> <location_pattern>")
	IF(NOT ("${ARGC}" EQUAL 2))
		MESSAGE(SEND_ERROR ${HEADER_DIRECTORIES_usage})
   	ELSE()
    	FILE(GLOB_RECURSE new_list "${location_pattern}")
    	SET(dir_list "")
    	FOREACH(file_path ${new_list})
        	GET_FILENAME_COMPONENT(dir_path ${file_path} PATH)
        	SET(dir_list ${dir_list} ${dir_path})
    	ENDFOREACH()
	ENDIF()
    LIST(REMOVE_DUPLICATES dir_list)
    SET(${return_list} ${dir_list})
ENDMACRO()

MACRO(SEARCH_FILES return_list location_pattern)
	SET(SEARCH_FILES_usage "SEARCH_FILES(<return_list> <location_pattern>")
	IF(NOT ("${ARGC}" EQUAL 2))
		MESSAGE(SEND_ERROR ${SEARCH_FILES_usage})
   	ELSE()
    	FILE(GLOB_RECURSE new_list "${location_pattern}")
	ENDIF()
    LIST(REMOVE_DUPLICATES new_list)
    SET(${return_list} ${new_list})
ENDMACRO()

MACRO(CONFIG_VERSION name namespace type)
	include(CMakePackageConfigHelpers)
	# Create the FlameManConfig.cmake and FlameManConfigVersion files
	if(WIN32 AND NOT CYGWIN)
	  set(CMAKE_DIR_SLICE ${PROJECT_NAME}/cmake)
	else()
	  set(CMAKE_DIR_SLICE lib/cmake/${PROJECT_NAME})
	endif()	

	# version config is the the same for build and installtion (-> only generated once)
	set(ConfigVersion "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_DIR_SLICE}/${PROJECT_NAME}ConfigVersion.cmake")
	write_basic_package_version_file(${ConfigVersion}
        	VERSION ${${PROJECT_NAME}_VERSION}
        	COMPATIBILITY AnyNewerVersion )

	#=========================================#
	#  generating installation configuration  #
	#=========================================#

	# the following allows relocating the installation, that is changing ${CMAKE_INSTALL_PREFIX}/
	# after the installation is done! In the generated configuration file this location is called
	# ${PACKAGE_PREFIX_DIR}
	set(set_check 1)
	set(${PROJECT_NAME}_Config ${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in) # input path
	# installation config path is constructed such that the file will not be found by cmake in the build tree
	set(InstallConfig "${CMAKE_CURRENT_BINARY_DIR}/install_config/${PROJECT_NAME}/${PROJECT_NAME}Config.cmake")
	set(ConfigPackageLocation ${INSTALL_CMAKE_DIR_REL}) # package name is neglected for simplicity

	#check whether the current project is a binary or a library
	IF(${type} STREQUAL "binary")

		# install configuration file pointing the installation
		configure_package_config_file(${${PROJECT_NAME}_Config} ${InstallConfig}
			# below, the destination for installing the configuration file
			# relative paths are relative to ${CMAKE_INSTALL_PREFIX}/some/installation/location/
			# where 'some/installation/location/' is the destination in the install command
			INSTALL_DESTINATION ${ConfigPackageLocation}
			# absolut paths must contain ${CMAKE_INSTALL_PREFIX}/
			# relative paths are relative to ${CMAKE_INSTALL_PREFIX}/
			PATH_VARS INSTALL_BIN_DIR ConfigPackageLocation)

		# make target available after installing the package
		install(TARGETS ${executable} EXPORT ${PROJECT_NAME}Targets DESTINATION ${INSTALL_BIN_DIR_REL} COMPONENT "${name}")

	ELSEIF(${type} STREQUAL "library")

		# install configuration file pointing the installation
		configure_package_config_file(${FlameMasterLibs_Config} ${InstallConfig}
			# below, the destination for installing the configuration file
			# relative paths are relative to ${CMAKE_INSTALL_PREFIX}/some/installation/location/
			# where 'some/installation/location/' is the destination in the install command
			INSTALL_DESTINATION ${ConfigPackageLocation}
			# absolut paths must contain ${CMAKE_INSTALL_PREFIX}/
			# relative paths are relative to ${CMAKE_INSTALL_PREFIX}/
			PATH_VARS INSTALL_INCLUDE_DIR INSTALL_LIB_DIR ConfigPackageLocation)

	ELSE(${type} STREQUAL "binary")
		
		message(ERROR "Unknown type: type has to be either 'binary' or 'library'!")

	ENDIF(${type} STREQUAL "binary")

	install(EXPORT ${PROJECT_NAME}Targets
		FILE ${PROJECT_NAME}Targets.cmake
		NAMESPACE ${namespace}
		DESTINATION ${ConfigPackageLocation} COMPONENT "${name}")

	# Install the <name>Config.cmake and <name>ConfigVersion.cmake
	install(FILES
		${InstallConfig}
		${ConfigVersion}
		DESTINATION ${ConfigPackageLocation} COMPONENT "${name}")

	IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_VERSION_PATCH} GREATER 3.0.2)
		set(set_check 0)
		set(ConfigPackageLocation ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_DIR_SLICE})
		set(BuildConfig ${ConfigPackageLocation}/${PROJECT_NAME}Config.cmake)
		set(BuildTargetsFile ${ConfigPackageLocation}/${PROJECT_NAME}Targets.cmake)
		export(EXPORT ${PROJECT_NAME}Targets FILE "${BuildTargetsFile}" NAMESPACE ${namespace})

		set(BuildConfig "${ConfigPackageLocation}/${PROJECT_NAME}Config.cmake")

		IF(${type} STREQUAL "binary")
			# build configuration file pointing to the binary target build variables
			set(directory ${CMAKE_CURRENT_BINARY_DIR})
		ElSEIF(${type} STREQUAL "library")
			HEADER_DIRECTORIES(FMLibs_src_header_direcotries "${PROJECT_SOURCE_DIR}/*.h")
			set(FMLibs_build_lib_locations ${build_lib_locations})
		ENDIF(${type} STREQUAL "binary")
		
		configure_package_config_file(${${PROJECT_NAME}_Config} "${BuildConfig}"
			INSTALL_DESTINATION ${ConfigPackageLocation}
			PATH_VARS INSTALL_INCLUDE_DIR INSTALL_LIB_DIR ConfigPackageLocation)

		export(PACKAGE ${PROJECT_NAME})
		MESSAGE (STATUS "Export ${PROJECT_NAME} build tree (cmake version > 3.0.2)")

	ELSE (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_VERSION_PATCH} GREATER 3.0.2)
   		
		MESSAGE (STATUS "No export of the ${PROJECT_NAME} build tree. Ancient cmake, use should update if you can (cmake version < 3.0.2)")

	ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_VERSION_PATCH} GREATER 3.0.2)
ENDMACRO(CONFIG_VERSION)

macro(USE_CXX_11)
  # We consider the following list of supported compilers (as of cmake version 3.6)
  # as sufficient to use the CMAKE_C_STANDARD feature:
  # https://cmake.org/cmake/help/v3.6/manual/cmake-compile-features.7.html#id6
  # (cf. bottom of the page)
  if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_VERSION_PATCH} LESS 3.6.3)
    message(STATUS "I hope your C++ compiler is more recent than your CMake!")
    # dirty fix to make this work with old cmake
    include(CheckCXXCompilerFlag)
    CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
    CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
    if(COMPILER_SUPPORTS_CXX11)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    elseif(COMPILER_SUPPORTS_CXX0X)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
    else()
          message(ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
    endif()
  else()
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON) 
  endif()
endmacro(USE_CXX_11)

macro(USE_C11)
  # We consider the following list of supported compilers (as of cmake version 3.6)
  # as sufficient to use the CMAKE_C_STANDARD feature:
  # https://cmake.org/cmake/help/v3.6/manual/cmake-compile-features.7.html#id6
  # (cf. bottom of the page)
  if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_VERSION_PATCH} LESS 3.6.3)
    message(STATUS "I hope your C++ compiler is more recent than your CMake!")
    # dirty fix to make this work with old cmake
    include(CheckCCompilerFlag)
    CHECK_C_COMPILER_FLAG("-std=c11" COMPILER_SUPPORTS_C11)
    CHECK_C_COMPILER_FLAG("-std=c0x" COMPILER_SUPPORTS_C0X)
    if(COMPILER_SUPPORTS_C11)
      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
    elseif(COMPILER_SUPPORTS_C0X)
      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c0x")
    else()
          message(ERROR "The compiler ${CMAKE_C_COMPILER} has no C11 support. Please use a different C compiler.")
    endif()
  else()
    set(CMAKE_C_STANDARD 11)
    set(CMAKE_C_STANDARD_REQUIRED ON) 
  endif()
endmacro(USE_C11)

macro(PRINT_SUNDIALS_HINT_INSTALL)
message(STATUS "Sundials installation hint:\n
        FlameMaster can install sundials for you (BETA).
        Run the configuration again with the INSTALL_SUNDIALS option set to ON.\n
        Example:
        cmake ../Repository -DINSTALL_SUNDIALS=ON
    ")
endmacro(PRINT_SUNDIALS_HINT_INSTALL)

macro(PRINT_SUNDIALS_HINT_ENV)
    message(STATUS "Sundials installation hint:\n
        You can link against a specific sundials installation by setting the 
        PATH_SUNDIALS_ROOT environment variable. You have to remove the 
        CMakeCache of your current build, if you already found sundials 
        before.\n
        Example for a command-line running zsh or bash in the Build directory:
        rm -rf *
        PATH_SUNDIALS_ROOT=/usr/local/Cellar/sundials/2.7.0_2
        cmake ../Repository -DCMAKE_BUILD_TYPE=Release
        ...
        ")
endmacro(PRINT_SUNDIALS_HINT_ENV)
